/*
 * BlipClient.java
 *
 * Created on 7 październik 2007, 13:07
 *
 */

package kosciak.blip4j;

import java.net.URL;
import java.util.ArrayList;
import java.util.List;

/**
 * <CODE>BlipClient</CODE> object is used to communicate with Blip.pl API.
 * It's an abstract class - there must be a class that implements the methods using specific Blip API version.
 * @author Wojtek 'KosciaK' Pietrzok
 * @since 0.1
 */
public abstract class BlipClient {

    private String username;
    private String password;
    private String userAgent = "Blip4j version 0.1";
    
    /**
     * Creates a new instance of BlipClient
     * @param username an login name of a User
     * @param password a password of a User
     * @throws kosciak.blip4j.BlipException if an error occurs (for example wrong username or password)
     */
    protected BlipClient(String username, String password) throws BlipException {
        this.username = username;
        this.password = password;
    }
    
    /**
     * Gets a password
     * @return a password
     */
    protected String getPassword() {
        return password;
    }

    /**
     * Gets a login name
     * @return a login name
     */
    protected String getUsername() {
        return username;
    }

    /**
     * Sets User Agent - how a software introduce itself
     * @param userAgent a name of an User Agent
     */
    public void setUserAgent(String userAgent){
        this.userAgent = userAgent + " using " + this.userAgent;
    }
    
    /**
     * Gets User Agent
     * @return get a name of User Agent
     */
    protected String getUserAgent(){
        return userAgent;
    }
    
    /**
     * Checks if authorization data is correct. If not it will throw BlipException with WrongAuthorizationData error.
     * @throws kosciak.blip4j.BlipException when Authorization data is invalid
     */
    protected void checkAuthorization() throws BlipException {
        try {
            getUser(getUsername());
        } catch (BlipException ex) {
            throw new BlipException(BlipError.AuthorizationError);
        }
    }
    
    /**
     * Divides Update bodies longer then allowed by Blip.pl API into parts.
     * Every part has a part count in format [x/Y] where x is a part number, Y is total number of parts.
     * @param body the body (content) of the Update
     * @param maxLength a max length of the body allowed by Blip.pl API
     * @return a list of body parts.
     */
    protected List<String> divideBody(String body, int maxLength) {
        List<String> parts = new ArrayList<String>();
        int length = body.length(); 
                
        if (length <= maxLength)
            parts.add(body);
        else {
            while (body.length() > maxLength - 8) {
                int end = body.lastIndexOf(' ', maxLength - 8);
                parts.add(body.substring(0, end));
                body = body.substring(end + 1);
            }
            if (body.length() > 0)
                parts.add(body);
            
            int size = parts.size();
            for (int i = 0 ; i < size ; i++) {
                parts.set(i, parts.get(i) + " [" + (i + 1) + "/" + size + "]");
            }
        }
        return parts;
    }
    
    /**
     * Gets the version of Blip.pl API BlipClient is using
     * @return Blip.pl API version
     */
    public abstract String getAPIVersion();
        
    /**
     * Sets your Status
     * @param body body of the Status to be set
     * @return an Id of created Status
     * @throws kosciak.blip4j.BlipException if an error occurs
     */
    public abstract int setStatus(String body) throws BlipException; 
        
    /**
     * Sets your Status.
     * Allows setting longer Statuses by dividing them.
     * @param body body of the Status to be set
     * @param allowLonger divides longer Statuses if true
     * @return an Id of created Status
     * @throws kosciak.blip4j.BlipException if an error occurs
     */
    public abstract int setStatus(String body, boolean allowLonger) throws BlipException; 
    
    /**
     * Sends Direct Message to a User
     * @param body body of the Status to be set
     * @param user an User to whom send a Direct Message
     * @return an Id of created Status
     * @throws kosciak.blip4j.BlipException if an error occurs
     */
    public abstract int sendDirectMessage(User user, String body) throws BlipException; 
    
    /**
     * Sends Direct Message to a User
     * Allows setting longer DirectMessages by dividing them.
     * @param body body of the Status to be set
     * @param user an User to whom send a Direct Message
     * @param allowLonger divides longer Statuses if true
     * @return an Id of created Status
     * @throws kosciak.blip4j.BlipException if an error occurs
     */
    public abstract int sendDirectMessage(User user, String body, boolean allowLonger) throws BlipException; 
    
    /**
     * Gets List of friends
     * @return a list of friends
     * @throws kosciak.blip4j.BlipException if an error occurs
     */
    public abstract List<User> getFriends() throws BlipException; 
    
    /**
     * Gets a list of friends of a User
     * @param user an User whose friends to list
     * @return User's friends list
     * @throws kosciak.blip4j.BlipException if an error occurs
     */
    public abstract List<User> getUserFriends(User user) throws BlipException; 
    
    /**
     * Gets User with a provided Id
     * @param userId an Id of a User
     * @return an User with provided Id
     * @throws kosciak.blip4j.BlipException if an error occurs
     */
    public abstract User getUser(int userId) throws BlipException; 

    /**
     * Gets User with a provided login name
     * @param userLogin a Login of a User
     * @return an User with provided Id
     * @throws kosciak.blip4j.BlipException if an error occurs
     */
    public abstract User getUser(String userLogin) throws BlipException; 
   
    /**
     * Gets current Status of a User
     * @param user an User whose Status you want to get
     * @return a current Status of this User
     * @throws kosciak.blip4j.BlipException if an error occurs
     */
    public abstract Update getCurrentStatus (User user) throws BlipException;
    
    /**
     * Gets Update with provided Id
     * @param updateId an Id of an Update
     * @return an Update with provided Id
     * @throws kosciak.blip4j.BlipException if an error occurs
     */
    public abstract Update getUpdate(int updateId) throws BlipException; 
    
    /**
     * Gets your Updates
     * @return List of Updates
     * @throws kosciak.blip4j.BlipException if an error occurs
     */
    public abstract List<Update> poll() throws BlipException; 
    
    /**
     * Gets your Updates starting from Update with provided Id
     * @param updateId an Id of the Update to start from
     * @return List of Updates
     * @throws kosciak.blip4j.BlipException if an error occurs
     */
    public abstract List<Update> poll(int updateId) throws BlipException; 
    
    /**
     * Gets Statuses send by you only (no Direct Messages)
     * @return List of Statuses
     * @throws kosciak.blip4j.BlipException if an error occurs
     */
    public abstract List<Update> pollStatuses() throws BlipException; 
    
    /**
     * Gets Statuses sent by you only (no Direct Messages) starting from Status with provided Id
     * @param updateId an Id of the Status to start from
     * @return List of Statuses
     * @throws kosciak.blip4j.BlipException if an error occurs
     */
    public abstract List<Update> pollStatuses(int updateId) throws BlipException; 
    
    /**
     * Gets Updates from Bliposphere
     * @return List of Updates
     * @throws kosciak.blip4j.BlipException if an error occurs
     */
    public abstract List<Update> pollBliposphere() throws BlipException; 
    
    /**
     * Gets Updates from Bliposhpere starting from Update with provided Id
     * @param updateId an Id of the Update to start from
     * @return List of Updates
     * @throws kosciak.blip4j.BlipException if an error occurs
     */
    public abstract List<Update> pollBliposphere(int updateId) throws BlipException; 

    /**
     * Gets User's Updates. 
     * Only Updates and DirectMessages sent by this User, NOT DirectMessages sent to this User
     * @param user an User whose Updates to get
     * @return List of Updates
     * @throws kosciak.blip4j.BlipException if an error occurs
     */
    public abstract List<Update> pollUser(User user) throws BlipException; 
    
    /**
     * Gets User's Updates starting from Update with provided Id
     * @param user an User whose Updates to get
     * @param updateId an Id of the Update to start from
     * @return List of Updates
     * @throws kosciak.blip4j.BlipException if an error occurs
     */
    public abstract List<Update> pollUser(User user, int updateId) throws BlipException; 

    /**
     * Gets User's Statuses only (no Direct Messages)
     * @param user an User whose Statuses to get
     * @return List of Statuses
     * @throws kosciak.blip4j.BlipException if an error occurs
     */
    public abstract List<Update> pollUserStatuses(User user) throws BlipException; 
    
    /**
     * Gets your Statuses only (no Direct Messages) starting from Status with provided Id
     * @param user an User whose Statuses to get
     * @param updateId an Id of the Status to start from
     * @return List of Statuses
     * @throws kosciak.blip4j.BlipException if an error occurs
     */
    public abstract List<Update> pollUserStatuses(User user, int updateId) throws BlipException; 
    
    /**
     * Expands short link htpp://rdir.pl/
     * @param url an URL to expand
     * @return expanded URL
     * @throws kosciak.blip4j.BlipException if an error occurs
     */
    public abstract URL expandURL(String url) throws BlipException;
    
    /**
     * Deletes an Update
     * @param updateId an Id of an Update to be deleted
     * @throws kosciak.blip4j.BlipException if an error occurs
     * @throws java.lang.UnsupportedOperationException if an Operation is not supported by this version of Blip API
     */
    public abstract void deleteUpdate(int updateId) throws UnsupportedOperationException, BlipException;
   
    /**
     * Adds an User to friends list
     * @param user an User to be added
     * @throws kosciak.blip4j.BlipException if an error occurs
     * @throws java.lang.UnsupportedOperationException if an Operation is not supported by this version of Blip API
     */
    public abstract void addFriend(User user) throws UnsupportedOperationException, BlipException;
    
    /**
     * Removes an User from the friends list
     * @param user an User to be removed
     * @throws kosciak.blip4j.BlipException if an error occurs
     * @throws java.lang.UnsupportedOperationException if an Operation is not supported by this version of Blip API
     */
    public abstract void removeFriend(User user) throws UnsupportedOperationException, BlipException;
    
}
